/*
 * funciones.c
 *
 *  Created on: 24/09/2011
 *      Author: Ramiro - Matias
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "funciones.h"
#include "estructuras.h"
#include "cscan.h"

#define T 0//Trace
#define E 1//Escritura
#define L 2//Lectura
#define C 3//Clean - Va a terminar siendo un pedido de Escritura
#define N 4//Nulo

int tamanioArchivo (char* filepath)
{
	FILE *punteroDelArchivo;
	int tamanio;

	punteroDelArchivo = fopen(FILEPATH, "rb");
	fseek(punteroDelArchivo,0,SEEK_END);
	tamanio = ftell(punteroDelArchivo);

	return tamanio;
}

char* mapearArchivo(char* filepath, int tamanio)
{

	int fd;
	char* map;

	fd = open(filepath, O_RDWR);
	if (fd == -1)
	{
		perror("Error abriendo el archivo para lectura");
		exit(EXIT_FAILURE);
	}

    map = mmap(NULL,tamanio,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    posix_madvise(map,512,POSIX_MADV_SEQUENTIAL);

    if (map == MAP_FAILED)
    {
    	close(fd);
     	perror("Error al mapear el archivo");
    	exit(EXIT_FAILURE);
    }

    close(fd);
    return map;
}

char* leerSector(char* map, int numSector)
{
	char* sectorALeer;
	char* aux = (char*) malloc (512);

	sectorALeer = numSector * 512 + map;
	memcpy(aux, sectorALeer, 512);
	return aux;
}/*memcpy recibe 3 parametros, el primero es donde se quiere copias
  (la direccion del puntero donde iniciaria el sector), el segundo
   es de donde copio, por eso buscamos la direccion en donde comenzaria
   el sector en el archivo mapeado. El 3° parametro es cuanto queremos copiar
   (en bytes),como siempre van a ser sectores le pusimos 512*/

int escribirSector(char*map, char* buff, int numSector)
{
	int tamanio;
	char* sectorAEscribir;
	sectorAEscribir = (numSector * 512) + map;
	memcpy(sectorAEscribir, buff, 512);
	tamanio = tamanioArchivo (FILEPATH);
	msync (map, tamanio, MS_ASYNC);

	return 0;

}

/*void tratarSector(int numeroSec, config Conf, int pistaActual, int sectorActual)
{
	float t_salto, t_sector, tiempoQueTardo;
	int pistaSolic, sectorSolic, cantPistasTotales, cantSectoresTotales, i, e;
	cs cilSec;
	int numeroSectorSig, pistaSig, sectorSig;

	numeroSectorSig = colaDePedidos[1].numeroDeSector;

	pasarA_CS(numeroSec, Conf);

	pistaSolic=cilSec.cilindro;
	sectorSolic=cilSec.sector;

	cantPistasTotales=Conf.CHS.cilindros;
	cantSectoresTotales=Conf.CHS.sectores;
	t_salto=Conf.t_salto;
	t_sector=tiempoDeGiro(Conf);

	if((pistaActual==-1) || (sectorActual==-1))
	{//VER
		pistaActual=0;
		sectorActual=1;
	}//SI ES EL 1ER ELEMENTO DE LA COLA NO TENGO POS ACTUAL

	printf("Posicion actual: %i:%i\n", pistaActual, sectorActual);

	printf("Sector solicitado: %i:%i\n", pistaSolic, sectorSolic);
	printf("Sectores recorridos: ");

	for(i=pistaActual; i!=pistaSolic; i++)
	{
		if(i==cantPistasTotales)
		{
			i=0;
		}
		printf("%i:%i ", i, sectorActual);
	}

	for(e=sectorActual; e!=sectorSolic; e++)
	{
		if(e==cantSectoresTotales)
		{
			e=0;
		}
		printf("%i:%i ", i, e+1);
	}


	if(sectorActual==sectorSolic)
	{
		tiempoQueTardo=tiempoEntrePistas(pistaActual, pistaSolic, t_salto, cantPistasTotales);
		printf(" \n");
	} else {
		tiempoQueTardo=tiempoEntrePistas(pistaActual, pistaSolic, t_salto, cantPistasTotales)+tiempoEntreSectores(sectorActual, sectorSolic, t_sector, cantSectoresTotales);
		printf(" \n");
	}

	printf("Tiempo consumido: %.2f\n", tiempoQueTardo);
	pasarA_CS(numeroSectorSig, Conf);

	pistaSig=cilSec.cilindro;
	sectorSig=cilSec.sector;

	printf("Proximo sector: %i:%i\n", pistaSig, sectorSig);

}*/

config leerConfig (char* archivoDeConfiguracion){

	config Conf;
	char* saraza = (char*) malloc (20);
	FILE *punteroAConfig;
	punteroAConfig = fopen(archivoDeConfiguracion, "r+");


	fscanf(punteroAConfig, "%s %s", saraza, Conf.inicio);
	fscanf(punteroAConfig, "%s %i", saraza, &Conf.ip);
	fscanf(punteroAConfig, "%s %i", saraza, &Conf.puerto);
	fscanf(punteroAConfig, "%s %s", saraza, Conf.algoritmo);
	fscanf(punteroAConfig, "%s %s", saraza, Conf.pathSocketUnix);
	fscanf(punteroAConfig, "%s %i", saraza, &Conf.flaglog);
	fscanf(punteroAConfig, "%s %i", saraza, &Conf.identificador);
	fscanf(punteroAConfig, "%s %i.%i.%i", saraza, &Conf.CHS.cilindros, &Conf.CHS.cabezas, &Conf.CHS.sectores);
	fscanf(punteroAConfig, "%s %i", saraza, &Conf.t_lectura);
	fscanf(punteroAConfig, "%s %i", saraza, &Conf.t_escritura);
	fscanf(punteroAConfig, "%s %i", saraza, &Conf.RPM);
	fscanf(punteroAConfig, "%s %i", saraza, &Conf.t_salto);

	fclose (punteroAConfig);
	free (saraza);

	return Conf;

}

void iniciarCola (void)
{
	int i;
	for(i=0;i<30;i++)
	{
		colaDePedidos[i].numeroDeSector = -1;
		colaDePedidos[i].tipoDePedido = N;
		colaDePedidos[i].infoAEscribir = cleanBuffer;
	}

}
int espacioEnCola (void)
{
	int i=0;
	while (colaDePedidos[i].numeroDeSector!=-1)
	{
		if (i>=30){
			printf("La cola esta llena\n");
			return -1;
		}//si llega hasta 30 es que la cola esta completa
		++i;//Recorre la cola hasta que encuentra un lugar vacio

	}
	return i;
}

void cargarCola(int numSec, char tipo, char* Buffer)//cambio char* buff por la direccion del puntero del buffer
{
	int i;
	i = espacioEnCola();


	colaDePedidos[i].numeroDeSector = numSec;
	colaDePedidos[i].tipoDePedido = tipo;
	colaDePedidos[i].infoAEscribir = Buffer;
}

void tratarCola(char* map, config Conf)
{
char* bufferAnterior;
int posicionActual;
//int pistaActual=-1;
//int sectorActual=-1;
int numeroSec;
//cs cilSec;

	ordenarColaPedidos(Conf);//dependiendo del algoritmo

/*	posicionActual=posAct//posAct es la posicion que obtengo de ordenarColaPedidos(Conf)
	pasarA_CS(posicionActual, Conf);

	pistaActual=cilSec.cilindro;
	sectorActual=cilSec.sector; */

	while (colaDePedidos[0].numeroDeSector!=-1)//cuando encuentra N es que no hay mas pedidos y corta
	{

		switch(colaDePedidos[0].tipoDePedido)
		{
		case E:

			if((colaDePedidos[0].numeroDeSector == colaDePedidos[1].numeroDeSector) && ((colaDePedidos[0].tipoDePedido == E) && (colaDePedidos[1].tipoDePedido == E)))
			{
				free (colaDePedidos[0].infoAEscribir);
				//Hay que loguear que no escribio nada, no es asesino y no es asesino
			} else {
				escribirSector(map,colaDePedidos[0].infoAEscribir,colaDePedidos[0].numeroDeSector);

				if((colaDePedidos[0].numeroDeSector == colaDePedidos[1].numeroDeSector) && (colaDePedidos[1].tipoDePedido == L))
				{
					bufferAnterior = colaDePedidos[0].infoAEscribir;
				} else {
					free (colaDePedidos[0].infoAEscribir);
				}
			}


			break;

		case L:

			if(bufferAnterior!=NULL)
			{
				infoLeida = bufferAnterior;
			} else {
				infoLeida = leerSector(map,colaDePedidos[0].numeroDeSector);
				//send (....) enviar lo que se leyo
			}

			if((colaDePedidos[0].numeroDeSector == colaDePedidos[1].numeroDeSector) && (colaDePedidos[1].tipoDePedido == L))
			{
				bufferAnterior = infoLeida;
			} else {
				bufferAnterior = NULL;
			}

			break;

		case T:
			numeroSec=colaDePedidos[0].numeroDeSector;
			/*tratarSector(numeroSec, Conf, pistaActual, sectorActual);*/
			/*En caso de trace debe debe comunicarse con la consola y pasarle
			 la info que necesita mostrar en pantalla*/
			break;

		case C:
			escribirSector(map,cleanBuffer,colaDePedidos[0].numeroDeSector);
			//write (....) informarle a la consola que el sector fue seteado
			break;
		}

		posicionActual = colaDePedidos[0].numeroDeSector;//cambia el valor de posicion actual

		/*pasarA_CS(posicionActual, Conf);

		pistaActual=cilSec.cilindro;
		sectorActual=cilSec.sector;*/

		colaDePedidos[0].numeroDeSector=-1;//lo anula porque ya fue ejecutado
		ordenarColaPedidos (Conf);//ordena devuelta la cola quedando un pedido valido en el sector 0 (a no ser que se terminen los pedidos)

	}

}

void ordenarColaPedidos(config Conf)
{
	if ((strcmp(Conf.algoritmo,"C-Scan"))==0)
	{
	    ordenarCola(colaDePedidos, posicionActual, Conf.CHS);
	}
	else if ((strcmp(Conf.algoritmo,"F-Scan"))==0)
	{
	    //la funcion de F-Scan
	}
	else {
		printf("El sistema no reconce ese algoritmo de planificacion\n");

	}
}

float tiempoEntreSectores(int sector1, int sector2, float tiempoEnRecorrerSector, int sectoresTotales)
{
	float tiempoSectores;

	if(sector1<sector2)
	{
		tiempoSectores=(sector2-sector1)*tiempoEnRecorrerSector;
	} else {
		tiempoSectores=((sectoresTotales-sector1)+sector2)*tiempoEnRecorrerSector;
	}
	return tiempoSectores;
}

float tiempoEntrePistas(int pista1, int pista2, float tiempoEnRecorrerPista, int pistasTotales)
{
	float tiempoPistas;

	if (pista1<pista2)
	{
		tiempoPistas=(pista2-pista1)*tiempoEnRecorrerPista;
	} else {
		tiempoPistas=((pistasTotales-pista1)+pista2)*tiempoEnRecorrerPista;
	}
	return tiempoPistas;
}

float tiempoDeGiro (config Conf)
{
	float unaVuelta, tiempoGiro, RPM, sectores;
	RPM = (float) Conf.RPM;
	sectores = (float) Conf.CHS.sectores;

	unaVuelta = 60000 / RPM;
	tiempoGiro = unaVuelta / sectores;

	return tiempoGiro;
}//Nos das el tiempo que tarda en recorrer un sector dentro de una pista

ps pasarA_pistaSector (int numSector, config Conf)
{
	ps pistSec;
	int cilindros = Conf.CHS.cilindros;
	int sectores = Conf.CHS.sectores;

	pistSec.pista = numSector / sectores;//como son 2 enteros, el / da la parte entera
	pistSec.sector = (numSector % sectores) % sectores;//teniendo que Cabeza es siempre uno no se tiene en cuenta en la ecuacion

	return pistSec;
}
